<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>go[1]-程序结构 | Abel&#39;Blog</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="记录golang的程序结构相关知识。  1.函数定义 2.匿名函数 3.延迟调用 4.错误处理 5.panic recover 6.错误处理策略 7.流程控制 1.for statements 2. switch statements   8.导入包 9.组织结构 10.权限 11.初始化 12.内部包 13.依赖管理 14.程序的目录建议 defer详解  函数是对一系列语句打包的单元。 1.函">
<meta property="og:type" content="article">
<meta property="og:title" content="go[1]-程序结构">
<meta property="og:url" content="http://example.com/2020/11/03/2020/2020-11-03-go[1]-%E7%A8%8B%E5%BA%8F%E7%BB%93%E6%9E%84/index.html">
<meta property="og:site_name" content="Abel&#39;Blog">
<meta property="og:description" content="记录golang的程序结构相关知识。  1.函数定义 2.匿名函数 3.延迟调用 4.错误处理 5.panic recover 6.错误处理策略 7.流程控制 1.for statements 2. switch statements   8.导入包 9.组织结构 10.权限 11.初始化 12.内部包 13.依赖管理 14.程序的目录建议 defer详解  函数是对一系列语句打包的单元。 1.函">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://s3.ax1x.com/2020/11/20/DM5bm4.png">
<meta property="article:published_time" content="2020-11-02T16:00:00.000Z">
<meta property="article:modified_time" content="2021-07-28T08:13:23.179Z">
<meta property="article:author" content="Abel Sean">
<meta property="article:tag" content="golang">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://s3.ax1x.com/2020/11/20/DM5bm4.png">
  
    <link rel="alternate" href="/atom.xml" title="Abel&#39;Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  
<link rel="stylesheet" href="/css/style.css">

<meta name="generator" content="Hexo 5.4.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Abel&#39;Blog</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://example.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-2020/2020-11-03-go[1]-程序结构" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2020/11/03/2020/2020-11-03-go%5B1%5D-%E7%A8%8B%E5%BA%8F%E7%BB%93%E6%9E%84/" class="article-date">
  <time datetime="2020-11-02T16:00:00.000Z" itemprop="datePublished">2020-11-03</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      go[1]-程序结构
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>记录golang的程序结构相关知识。</p>
<ul>
<li><a href="#1%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89">1.函数定义</a></li>
<li><a href="#2%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0">2.匿名函数</a></li>
<li><a href="#3%E5%BB%B6%E8%BF%9F%E8%B0%83%E7%94%A8">3.延迟调用</a></li>
<li><a href="#4%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86">4.错误处理</a></li>
<li><a href="#5panic-recover">5.panic recover</a></li>
<li><a href="#6%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%E7%AD%96%E7%95%A5">6.错误处理策略</a></li>
<li><a href="#7%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6">7.流程控制</a><ul>
<li><a href="#1for-statements">1.for statements</a></li>
<li><a href="#2-switch-statements">2. switch statements</a></li>
</ul>
</li>
<li><a href="#8%E5%AF%BC%E5%85%A5%E5%8C%85">8.导入包</a></li>
<li><a href="#9%E7%BB%84%E7%BB%87%E7%BB%93%E6%9E%84">9.组织结构</a></li>
<li><a href="#10%E6%9D%83%E9%99%90">10.权限</a></li>
<li><a href="#11%E5%88%9D%E5%A7%8B%E5%8C%96">11.初始化</a></li>
<li><a href="#12%E5%86%85%E9%83%A8%E5%8C%85">12.内部包</a></li>
<li><a href="#13%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86">13.依赖管理</a></li>
<li><a href="#14%E7%A8%8B%E5%BA%8F%E7%9A%84%E7%9B%AE%E5%BD%95%E5%BB%BA%E8%AE%AE">14.程序的目录建议</a></li>
<li><a href="#defer%E8%AF%A6%E8%A7%A3">defer详解</a></li>
</ul>
<p>函数是对一系列语句打包的单元。</p>
<h1 id="1-函数定义"><a href="#1-函数定义" class="headerlink" title="1.函数定义"></a>1.函数定义</h1><p>func name(parameter-list)(result-list) {<br>    body<br>}<br>能支持多返回值，或者无返回值。匿名函数是指的没有名字的函数。函数可以成为一个结构体字段，也能成为通道来传递。<br>匿名函数是一种常见的重构手段。可以将大函数分解成多个相对独立的匿名函数块，这样主干部分的调用函数将会更加简洁，做到框架和细节分离。</p>
<h1 id="2-匿名函数"><a href="#2-匿名函数" class="headerlink" title="2.匿名函数"></a>2.匿名函数</h1><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">test</span><span class="params">(x <span class="keyword">int</span>)</span><span class="title">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">        fmt.Println(x)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    f := test(<span class="number">123</span>)</span><br><span class="line">    f()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过匿名函数将变量123缓存再函数中。最后调用的时候，可以很方便的将123输出。</p>
<blockquote>
<p>警告：捕获迭代变量Go词法作用于陷阱。即使经验丰富程序员也会在这个问题上犯错误。</p>
</blockquote>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> rmdirs []<span class="function"><span class="keyword">func</span><span class="params">()</span></span></span><br><span class="line"><span class="keyword">for</span> _,d := <span class="keyword">range</span> tempDirs() &#123;</span><br><span class="line">    dir := d</span><br><span class="line">    os.MkdirAll(dir,<span class="number">0755</span>)</span><br><span class="line">    rmdirs = <span class="built_in">append</span>(rmdirs,<span class="function"><span class="keyword">func</span><span class="params">()</span></span>&#123;</span><br><span class="line">        os.RemoveAll(dir)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> _,rmdir := <span class="keyword">range</span>(rmdirs&#123;</span><br><span class="line">     rmdir()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>为啥要将d重新赋值成dir？原因就在循环变量中的作用域。如果直接使用d将会删除的相同的目录。这样的问题在使用defer语句也有相同问题。</p>
<h1 id="3-延迟调用"><a href="#3-延迟调用" class="headerlink" title="3.延迟调用"></a>3.延迟调用</h1><p>defer语句是指注册一个函数，再稍后调用。一般用于资源释放，解锁，错误处理等操作。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span> <span class="params">()</span></span> &#123;</span><br><span class="line">f,err :=os.Open(<span class="string">&quot;./main.go&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err !=<span class="literal">nil</span> &#123;</span><br><span class="line">    fmt.Println(<span class="string">&quot;err&quot;</span>)</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">defer</span> f.<span class="built_in">close</span>() <span class="comment">// 提前注册释放</span></span><br><span class="line"><span class="comment">// 文件读写</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>延时调用遵循FILO，堆栈式的调用。简单理解就是先进后出。<br>错误的用法<br>func main() {<br>   for I := 0; I&lt;1000000; I++ {<br>        path := fmt.Sprintf(“./log/%d.txt”,i)<br>        f, err := os.Open(path)<br>        if err != nil {<br>            fmt.Println(err)<br>            continue<br>        }<br>        defer f.close() // 其实要等到这个循环全部做完，才会调用的<br>        // 操作文件<br>   }<br>}<br>这种情况，应该将操作文件的部分封装成小函数，避免再循环过程中，直接使用defer。<br>性能方面，defer方式需要花掉比较大的代价。</p>
<h1 id="4-错误处理"><a href="#4-错误处理" class="headerlink" title="4.错误处理"></a>4.错误处理</h1><p>调侃go的人，说错误处理有些返祖。”stuck in 70’s”。<br>提供了error的接口。<br>err := errors.New(“division by zero”)<br>这样就能构造一个出来。有经验的程序员一般都会对错误做一些预计的处理。函数如果返回类型为error时候，都需要判断一下错误信息是否为空。</p>
<h1 id="5-panic-recover"><a href="#5-panic-recover" class="headerlink" title="5.panic recover"></a>5.panic recover</h1><p>类似于exception/try/catch结构化异常。函数原型如下。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">panic</span><span class="params">(v <span class="keyword">interface</span>&#123;&#125;)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">recover</span><span class="params">()</span> <span class="title">interface</span></span>&#123;&#125;</span><br></pre></td></tr></table></figure>
<p>他们是内置函数，不是语句。panic将会终端当前流程（如：数组访问越界、空指针引用），并且触发defer的调用。在延时调用中可以通过recover捕获其中的报错。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">       <span class="keyword">if</span> err := <span class="built_in">recover</span>(); err!=<span class="literal">nil</span> &#123;</span><br><span class="line">          fmt.Println(err)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>recover必须在panic触发之后才能捕获到错误，而且只能在延时调用函数中才能工作。不能在函数内部直接使用。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">catch</span><span class="params">()</span></span> &#123;</span><br><span class="line">      log.Println(<span class="string">&quot;catch:&quot;</span>,<span class="built_in">recover</span>())</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">      <span class="keyword">defer</span> catch() <span class="comment">// 捕获</span></span><br><span class="line">      <span class="keyword">defer</span> log.Println(<span class="built_in">recover</span>())<span class="comment">// 失败</span></span><br><span class="line">      <span class="keyword">defer</span> <span class="built_in">recover</span>() <span class="comment">// 失败</span></span><br><span class="line">      <span class="built_in">panic</span>(<span class="string">&quot;i am dead&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>调试期间可以使用 runtime/debug.PrintStack。获取完整的堆栈信息。将会输出到标准错误日志中。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// PrintStack prints to standard error the stack trace returned by runtime.Stack.</span><br><span class="line">func PrintStack() &#123;</span><br><span class="line">	os.Stderr.Write(Stack())</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>使用panic的时候，建议是遇到了不可恢复、导致系统无法运行的错误，否则不要使用。服务器端口占用、文件无法打开、数据库未启动。这种错误超出了程序员的控制的。程序必须停止的情况。</p>
<h1 id="6-错误处理策略"><a href="#6-错误处理策略" class="headerlink" title="6.错误处理策略"></a>6.错误处理策略</h1><p>1.将错误信息上报给调用者，并且添加额外的上下文信息；错误信息最好能描述出问题的需要的参数；<br>2.如果错误是偶发的，或者是不可预计问题导致。我们需要构造有限次数的重试机制，避免无限制的重试；<br>3.出现错误之后，程序其实已经无法执行，那就需要将错误信息输出出来，并且将程序终止；避免出现更多的问题。比如数据库已经无法写入了，机器的硬盘已经无法写入文件内容了；<br>4.错误不致命，只需要在错误级别日志中输出，然后继续执行程序；<br>5.可以忽略掉一些无关紧要的错误。<br>在Go中，函数被当作第一类型（first-class values），函数像其他值一样，拥有类型，可以传送，赋值给其他变量。函数值不能做比较，所以不能当成map的key。</p>
<h1 id="7-流程控制"><a href="#7-流程控制" class="headerlink" title="7.流程控制"></a>7.流程控制</h1><h2 id="1-for-statements"><a href="#1-for-statements" class="headerlink" title="1.for statements"></a>1.for statements</h2><p>查看文档：</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// file:c:/go/doc/go_spec.html#For_statements</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 根据条件循环</span></span><br><span class="line"><span class="keyword">for</span> a &lt; b &#123;</span><br><span class="line">	a *= <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 用于做列表循环</span></span><br><span class="line">RangeClause = [ ExpressionList <span class="string">&quot;=&quot;</span> | IdentifierList <span class="string">&quot;:=&quot;</span> ] <span class="string">&quot;range&quot;</span> Expression .</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>标准目录为src、bin、pkg三个目录。<br>GOPATH可以指定几个目录，排在列表最前面的比当前工作空间优先级更高。go get默认会下载到第一个工作空间里面。备注：unix-like使用冒号分隔，windows使用;分割。<br>GOROOT指定工具链和标准库的存放位置。</p>
<h2 id="2-switch-statements"><a href="#2-switch-statements" class="headerlink" title="2. switch statements"></a>2. switch statements</h2><p><a target="_blank" rel="noopener" href="https://studygolang.com/articles/31379?fr=sidebar">fallthrough</a></p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;fmt&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := <span class="number">2</span></span><br><span class="line">    <span class="keyword">switch</span> a &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;a=1&quot;</span>)</span><br><span class="line">    <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;a=2&quot;</span>)</span><br><span class="line">        <span class="keyword">fallthrough</span></span><br><span class="line">    <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;a=3&quot;</span>)</span><br><span class="line">        <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;a=4&quot;</span>)</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">        fmt.Println(<span class="string">&quot;default&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="8-导入包"><a href="#8-导入包" class="headerlink" title="8.导入包"></a>8.导入包</h1><p>如果是系统级的包的导入</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import &quot;net/http&quot;</span><br><span class="line">import osx &quot;github.com/apple/osx/lib&quot;</span><br><span class="line">import _ &quot;github.com/qyuhen/test&quot;</span><br><span class="line">import &quot;../lib&quot; // 相对路径引入</span><br></pre></td></tr></table></figure>
<h1 id="9-组织结构"><a href="#9-组织结构" class="headerlink" title="9.组织结构"></a>9.组织结构</h1><p>包由一个或多个保存在同一目录下的源文件组成。<br>包名和目录名称并无关系，不要求保持一致，举个例子，leaf里面的go的库。目录名为go，但是里面的包使用的名称为g。不影响使用，在import的时候是写go,语句里面写g。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&quot;github.com/name5566/leaf/go&quot;</span><br><span class="line">d := g.New(10)</span><br></pre></td></tr></table></figure>
<p>同一目录下的包名需要完全一致。下列有几个特殊的包名：</p>
<blockquote>
<p>main ：可执行入口<br>all: 标准库以及 GOPATH中能找到的所有包。<br>std,cmd：标准库工具链<br>documentations：存储文档信息、无法导入。</p>
</blockquote>
<h1 id="10-权限"><a href="#10-权限" class="headerlink" title="10.权限"></a>10.权限</h1><p>包内成员可以互相访问。只有大写字母的能被包外访问。当然也能通过unsafe.Pointer方式来反出数据并且调用。</p>
<h1 id="11-初始化"><a href="#11-初始化" class="headerlink" title="11.初始化"></a>11.初始化</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">func init() &#123;</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure>
<h1 id="12-内部包"><a href="#12-内部包" class="headerlink" title="12.内部包"></a>12.内部包</h1><p>将内部模块分离出来，单独包的形式维护。只能被父目录下的包访问，命名为internal目录下的包。</p>
<h1 id="13-依赖管理"><a href="#13-依赖管理" class="headerlink" title="13.依赖管理"></a>13.依赖管理</h1><p> 主要是解决三方依赖库文件冲突问题。这个概念是和内部包刚好相反，vendor目录是提供给当前工作目录，通用的目录。<br>注意：vendor比标准库有嫌隙更高。</p>
<h1 id="14-程序的目录建议"><a href="#14-程序的目录建议" class="headerlink" title="14.程序的目录建议"></a>14.程序的目录建议</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">  |</span><br><span class="line">  | mgr.go</span><br><span class="line">  |</span><br><span class="line">  -----ixxx</span><br><span class="line">       |</span><br><span class="line">       |</span><br><span class="line">       -----imgr.go</span><br><span class="line">  |</span><br><span class="line">  |</span><br><span class="line">  -----models</span><br><span class="line">       |</span><br><span class="line">       |</span><br><span class="line">       ------mgr_impl.go</span><br></pre></td></tr></table></figure>

<p>mgr.go 用于放置提供给外部调用函数；外部需要使用的类；</p>
<p>ixxx 目录放置模块的接口定义；</p>
<p>models 目录放置实现函数；</p>
<p>图中说明了绘制了依赖关系。这样能防止再外面循环引用的问题：</p>
<h1 id="defer详解"><a href="#defer详解" class="headerlink" title="defer详解"></a>defer详解</h1><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://imgchr.com/i/DM5bm4"><img src="https://s3.ax1x.com/2020/11/20/DM5bm4.png" alt="DM5bm4.png"></a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2020/11/03/2020/2020-11-03-go[1]-%E7%A8%8B%E5%BA%8F%E7%BB%93%E6%9E%84/" data-id="ckrn3an6w000b20xwa1wke5pc" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/golang/" rel="tag">golang</a></li></ul>

    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2020/11/03/2020/2020-11-03-docker%5B0%5D-nginx/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          docker运行nginx
        
      </div>
    </a>
  
  
    <a href="/2020/11/03/2020/2020-11-03-go%5B0%5D-getstart/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">go[0]-入门</div>
    </a>
  
</nav>

  
</article>

</section>
        
          <aside id="sidebar">
  
    

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/3D/" rel="tag">3D</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/AI/" rel="tag">AI</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/C/" rel="tag">C++</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Game/" rel="tag">Game</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Go/" rel="tag">Go</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linux/" rel="tag">Linux</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Math/" rel="tag">Math</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Server/" rel="tag">Server</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Unreal-Engine4/" rel="tag">Unreal Engine4</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/" rel="tag">git</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/golang/" rel="tag">golang</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/guitar/" rel="tag">guitar</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/node-js/" rel="tag">node.js</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/" rel="tag">protobuf</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/python/" rel="tag">python</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/recast/" rel="tag">recast</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/" rel="tag">redis</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/type/" rel="tag">type</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/vscode/" rel="tag">vscode</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BF%90%E7%BB%B4/" rel="tag">运维</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/3D/" style="font-size: 10px;">3D</a> <a href="/tags/AI/" style="font-size: 11.67px;">AI</a> <a href="/tags/C/" style="font-size: 15px;">C++</a> <a href="/tags/Game/" style="font-size: 18.33px;">Game</a> <a href="/tags/Go/" style="font-size: 13.33px;">Go</a> <a href="/tags/Linux/" style="font-size: 13.33px;">Linux</a> <a href="/tags/Math/" style="font-size: 11.67px;">Math</a> <a href="/tags/Server/" style="font-size: 16.67px;">Server</a> <a href="/tags/Unreal-Engine4/" style="font-size: 10px;">Unreal Engine4</a> <a href="/tags/git/" style="font-size: 10px;">git</a> <a href="/tags/golang/" style="font-size: 20px;">golang</a> <a href="/tags/guitar/" style="font-size: 10px;">guitar</a> <a href="/tags/node-js/" style="font-size: 10px;">node.js</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/python/" style="font-size: 10px;">python</a> <a href="/tags/recast/" style="font-size: 11.67px;">recast</a> <a href="/tags/redis/" style="font-size: 10px;">redis</a> <a href="/tags/type/" style="font-size: 10px;">type</a> <a href="/tags/vscode/" style="font-size: 10px;">vscode</a> <a href="/tags/%E8%BF%90%E7%BB%B4/" style="font-size: 16.67px;">运维</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/06/">June 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/04/">April 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/03/">March 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/01/">January 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/12/">December 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/11/">November 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">March 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/11/">November 2018</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/07/19/2021/2021-07-19-etcd-learn/">go-etcd阅读笔记</a>
          </li>
        
          <li>
            <a href="/2021/07/19/2021/2021-07-19-socketop-learn/">REUSEPORT-REUSEADDR-学习</a>
          </li>
        
          <li>
            <a href="/2021/06/22/2021/2021-06-22-go-ethereum-learn/">go-ethereum阅读笔记</a>
          </li>
        
          <li>
            <a href="/2021/06/21/2021/2021-06-21-server%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/">server测试工具</a>
          </li>
        
          <li>
            <a href="/2021/06/09/2021/2021-06-09-pprof-doc/">go-pprof</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2021 Abel Sean<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>


  
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css">

  
<script src="/fancybox/jquery.fancybox.pack.js"></script>




<script src="/js/script.js"></script>




  </div>
</body>
</html>